﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Xml;

namespace SHomeWorkshop.LunarPresentation.Commands
{
    public partial class Command
    {
        /// <summary>
        /// 插入公式。默认插入在当前公式后面（下侧）。
        /// </summary>
        /// <param name="destExType">公式类型。</param>
        /// <param name="destExXmlText">公式后台Xml文本，通常是定义在资源文件中的某个字符串。
        /// 注意类型必须相符！！！</param>
        private static Expressions.Expression InsertExpression(TypeOfExpression destExType,
            string destExXmlText)
        {
            return InsertExpression(destExType, destExXmlText, true);
        }

        /// <summary>
        /// 插入公式。
        /// </summary>
        /// <param name="destExType">公式类型。</param>
        /// <param name="destExXmlText">公式后台Xml文本，通常是定义在资源文件中的某个字符串。
        /// <para name="insertAtBottom">插入位置，在当前公式前面（上侧）还是后面（下侧）。</para>
        /// 注意类型必须相符！！！</param>
        /// <param name="insertAtBottom">是否在底部插入。</param>
        /// <param name="mi">传入“撤销”与“重做”列表项。以防止需要多步才能撤销。
        /// 如果mi不为空，则不会在“撤销列表”中添加（插入公式）这一Action。</param>
        public static Expressions.Expression InsertExpression(TypeOfExpression destExType,
            string destExXmlText, bool insertAtBottom, ModifingItem mi = null)
        {
            if (Globals.selectedEditor == null) return null;
            if (Globals.selectedEditor.SelectedExpression == null)
            {
                System.Windows.MessageBox.Show("请先选取一个公式，然后再执行此操作。新公式将出现在选中公式的后面！",
                    Globals.appName, System.Windows.MessageBoxButton.OK,
                    System.Windows.MessageBoxImage.Warning);
                return null;
            }

            LunarPresentation.Expressions.Expression curEx = Globals.selectedEditor.SelectedExpression;

            if (mi != null)
            {
                mi.OldSelectedExID = curEx.ExID;
            }

            if (curEx is Expressions.SubPanel)
            {
                //System.Windows.MessageBox.Show("不能在子面板后面插入新公式，请选择其它位置！",
                //    Globals.appName, System.Windows.MessageBoxButton.OK,
                //    System.Windows.MessageBoxImage.Warning);
                //return null;

                Expressions.SubPanel subPanel = curEx as Expressions.SubPanel;
                if (subPanel.BasePanel != null && subPanel.BasePanel.Children.Count > 0 &&
                    subPanel.BasePanel.Children[subPanel.BasePanel.Children.Count - 1] is Expressions.Expression)
                {
                    curEx = subPanel.BasePanel.Children[subPanel.BasePanel.Children.Count - 1] as Expressions.Expression;
                }
                else
                {
                    System.Windows.MessageBox.Show("子面板中无公式，无法执行插入公式操作！",
                        Globals.appName, System.Windows.MessageBoxButton.OK,
                        System.Windows.MessageBoxImage.Warning);
                    return null;
                }
            }

            if (curEx.Parent is StackPanel)
            {
                StackPanel spanel = curEx.Parent as StackPanel;

                int destIndex = spanel.Children.IndexOf(curEx);

                if (insertAtBottom)
                {
                    if (curEx is Expressions.BaseText)
                    {
                        Expressions.BaseText bt = curEx as Expressions.BaseText;
                        if (bt.IsHeaderText && bt.IsCollapsed)
                        {
                            //寻找下一个可见的公式。其索引就是目标索引。
                            int tmpIndex = destIndex + 1;
                            Expressions.Expression nextVisibleEx = null;
                            while (tmpIndex < spanel.Children.Count - 1)
                            {
                                tmpIndex += 1;
                                Expressions.Expression tmpEx = spanel.Children[tmpIndex] as Expressions.Expression;
                                if (tmpEx.Visibility == Visibility.Visible)
                                {
                                    nextVisibleEx = tmpEx;
                                    break;
                                }
                            }

                            if (nextVisibleEx != null)
                            {
                                destIndex = tmpIndex;
                            }
                            else { destIndex = spanel.Children.Count; }//直接在最后插入新公式。
                        }
                        else { destIndex += 1; }
                    }
                    else
                    {
                        destIndex += 1;
                    }
                }

                XmlNode newExXmlData = curEx.XmlData.ParentNode.InsertXmlAt(destExXmlText, destIndex);
                if (newExXmlData == null)
                {
                    MessageBox.Show("发生意外！插入公式时未能在指定位置插入Xml节点。",
                        Globals.appName, MessageBoxButton.OK, MessageBoxImage.Warning);
                    return null;
                }

                // 这里是关键。
                Expressions.Expression newExpression = BuildNewExForInsert(destExType, curEx);

                if (newExpression != null)
                {
                    //int exIndex = -1;
                    if (insertAtBottom)
                    {
                        //exIndex = spanel.Children.IndexOf(curEx) + 1;
                        spanel.Children.Insert(destIndex, newExpression);
                    }
                    else
                    {
                        //exIndex = spanel.Children.IndexOf(curEx);
                        spanel.Children.Insert(destIndex, newExpression);//在当前公式顶部（上侧插入）。
                    }

                    newExpression.XmlData = newExXmlData;

                    #region 准备“撤销”与“重做”所需要的数据。
                    Type newExType = newExpression.GetType();

                    if (mi == null)
                    {
                        mi = new ModifingItem();

                        //如果mi不为空，则不会在“撤销列表”中添加（插入公式）这一Action。
                        Action insertEx = new Action(newExpression.ExID, destIndex, newExType.Name,
                            "InsertExpression", null, newExpression.XmlData.OuterXml, ActionType.Insert,
                            curEx.ParentPanel.ExID);
                        mi.Add(insertEx);
                    }

                    Action indentEx = new Action(newExpression.ExID, destIndex, newExType.Name,
                        "Indent", newExpression.Indent.ToString(), curEx.Indent.ToString());
                    mi.Add(indentEx);
                    #endregion

                    newExpression.Indent = curEx.Indent;// 插入新公式时自动同步缩进。

                    //对于插入操作来说，重做时是需要考虑缩进的。

                    //加入“撤销”与“重做”列表。
                    newExpression.Editor.Do(mi);

                    mi.NewSelectedExID = newExpression.ExID;

                    Globals.selectedEditor.SelectedExpression = newExpression;

                    Globals.selectedEditor.IsModified = true;

                    //Globals.TryToShowExpression(newExpression);//选中公式时自动显示。

                    return newExpression;
                }
            }

            return null;
        }

        private static Expressions.Expression BuildNewExForInsert(TypeOfExpression destExType,
            Expressions.Expression curEx)
        {
            Expressions.Expression newExpression = null;
            switch (destExType)// 此处不需要支持所有公式类型。
            {
                case TypeOfExpression.Arrow:
                    {
                        newExpression = new LunarPresentation.Expressions
                            .Arrow(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.Brace:
                    {
                        newExpression = new LunarPresentation.Expressions
                            .Brace(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.Bracket:
                    {
                        newExpression = new LunarPresentation.Expressions
                            .Bracket(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.BaseText:
                    {
                        newExpression = new LunarPresentation.Expressions
                            .BaseText(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.Expander:
                    {
                        newExpression = new LunarPresentation.Expressions
                            .Expander(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.Grid:
                    {
                        newExpression = new LunarPresentation.Expressions
                            .Grid(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.PictureBox:
                    {
                        newExpression = new LunarPresentation.Expressions
                            .PictureBox(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.Triangle:
                    {
                        newExpression = new LunarPresentation.Expressions
                        .Triangle(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.LogicCross:
                    {
                        newExpression = new LunarPresentation.Expressions
                        .LogicCross(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.LogicGenuspecies:
                    {
                        newExpression = new LunarPresentation.Expressions
                        .LogicGenuspecies(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.LogicContradiction:
                    {
                        newExpression = new LunarPresentation.Expressions
                        .LogicContradiction(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.MarkText:
                    {
                        newExpression = new LunarPresentation.Expressions
                        .MarkText(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.RichText:
                    {
                        newExpression = new LunarPresentation.Expressions
                        .RichText(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.Row:
                    {
                        newExpression = new LunarPresentation.Expressions
                        .Row(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                case TypeOfExpression.Tree:
                    {
                        newExpression = new LunarPresentation.Expressions
                        .Tree(curEx.RootPanel, curEx.ParentPanel, curEx.Editor); break;
                    }
                // TODO 如果插入新增公式类型，需要在此处添加。
            }
            return newExpression;
        }

        public static Expressions.Arrow InsertArrow()
        {
            return InsertExpression(TypeOfExpression.Arrow,
                LunarPresentation.Properties.Resources.Arrow) as Expressions.Arrow;
        }

        public static Expressions.Brace InsertBrace(bool isEndBrace = false)
        {
            if (isEndBrace)
            {
                return InsertExpression(TypeOfExpression.Brace,
                    LunarPresentation.Properties.Resources.EndBrace) as Expressions.Brace;
            }
            else
            {
                return InsertExpression(TypeOfExpression.Brace,
                    LunarPresentation.Properties.Resources.Brace) as Expressions.Brace;
            }
        }

        public static Expressions.Bracket InsertBracket()
        {
            return InsertExpression(TypeOfExpression.Bracket,
                LunarPresentation.Properties.Resources.Bracket) as Expressions.Bracket;
        }

        public static Expressions.BaseText InsertBaseText(bool insertAfter = true, ModifingItem mi = null)
        {
            if (insertAfter)
            {
                return InsertExpression(TypeOfExpression.BaseText,
                    LunarPresentation.Properties.Resources.BaseText, true, mi) as Expressions.BaseText;
            }
            else
            {
                return InsertExpression(TypeOfExpression.BaseText,
                    LunarPresentation.Properties.Resources.BaseText, false, mi) as Expressions.BaseText;
            }
        }

        public static Expressions.Grid InsertGrid()
        {
            return InsertExpression(TypeOfExpression.Grid,
                LunarPresentation.Properties.Resources.Grid) as Expressions.Grid;
        }

        public static Expressions.RichText InsertRichText(bool insertAfter = true, ModifingItem mi = null)
        {
            if (insertAfter)
            {
                return InsertExpression(TypeOfExpression.RichText,
                    LunarPresentation.Properties.Resources.RichText, true, mi) as Expressions.RichText;
            }
            else
            {
                return InsertExpression(TypeOfExpression.RichText,
                    LunarPresentation.Properties.Resources.RichText, false, mi) as Expressions.RichText;
            }
        }

        public static Expressions.Expander InsertExpander()
        {
            return InsertExpression(TypeOfExpression.Expander,
                 LunarPresentation.Properties.Resources.Expander) as Expressions.Expander;
        }

        public static Expressions.PictureBox InsertPictureBox(bool insertAtBottom = true)
        {
            return InsertExpression(TypeOfExpression.PictureBox,
                 LunarPresentation.Properties.Resources.PictureBox, insertAtBottom) as Expressions.PictureBox;
        }

        public static Expressions.Triangle InsertTriangle()
        {
            return InsertExpression(TypeOfExpression.Triangle,
                 LunarPresentation.Properties.Resources.Triangle) as Expressions.Triangle;
        }

        public static Expressions.LogicCross InsertLogicCross()
        {
            return InsertExpression(TypeOfExpression.LogicCross,
                 LunarPresentation.Properties.Resources.LogicCross) as Expressions.LogicCross;
        }

        public static Expressions.LogicGenuspecies InsertLogicGenuspecies()
        {
            return InsertExpression(TypeOfExpression.LogicGenuspecies,
                 LunarPresentation.Properties.Resources.LogicGenuspecies) as Expressions.LogicGenuspecies;
        }

        public static Expressions.LogicContradiction InsertLogicContradiction()
        {
            return InsertExpression(TypeOfExpression.LogicContradiction,
                 LunarPresentation.Properties.Resources.LogicContradiction) as Expressions.LogicContradiction;
        }

        public static Expressions.MarkText InsertMarkText()
        {
            return InsertExpression(TypeOfExpression.MarkText,
                 LunarPresentation.Properties.Resources.MarkText) as Expressions.MarkText;
        }

        public static Expressions.Row InsertRow()
        {
            return InsertExpression(TypeOfExpression.Row,
                LunarPresentation.Properties.Resources.Row) as Expressions.Row;
        }

        public static Expressions.Tree InsertTree()
        {
            return InsertExpression(TypeOfExpression.Tree,
                LunarPresentation.Properties.Resources.Tree) as Expressions.Tree;
        }

        /// <summary>
        /// 水平线，本质上是一个没有箭头的箭头式。
        /// </summary>
        /// <returns></returns>
        public static Expressions.Arrow InsertHorizontalLine()
        {
            return InsertExpression(TypeOfExpression.Arrow,
                LunarPresentation.Properties.Resources.HorizontalLine) as Expressions.Arrow;
        }

        //TODO 如果有新公式类型，需要在此处添加相应方法。
    }
}
